package com.zx.shiro.handlers;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresGuest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;

import com.zx.shiro.service.ShiroService;
import com.zx.shiro.session.MySessionDao;

@RequestMapping("/shiro")
@Controller
public class ShiroHandler {
	
	@Autowired
	ShiroService shiroService;
	
	@Autowired
	MySessionDao sessionDAO;
	
	@RequestMapping("/testSession")
	public String testSession(Model model){
		System.out.println("sessionList : " + MySessionDao.sessionList);
		return "list";
	}
	
	/**
	 * 测试Shiro权限控制（使用注解方式）
	 * 
	 * 权限注解：
	 * 1).@RequiresAuthentication : 已经认证（即登录）
	 * 2).@RequiresUser : 已经认证（即登录）或者通过记住我登录的
	 * 3).@RequiresGuest : 没有认证（登录）或者通过记住我登录的，即是游客身份
	 * 4).@RequiresRoles(value={"admin", "user"}, logical=Logical.AND) : 表示需要角色admin和user
	 * 5).@RequiresPermissions(value={"user:add", "user:edit"}, logical=Logical.OR) :　表示需要权限user:add 或 user:edit
	 * 
	 * @return
	 */
	@RequestMapping("/testShiroAnnotation")
	@RequiresRoles(value={"admin", "user"}, logical=Logical.AND)
	public String testShiroAnnotation(HttpSession session){
		session.setAttribute("key", "value12345");
		shiroService.testMethod();
		return "redirect:/list.jsp";
	}
	
	/**
	 * 统一处理没有权限异常
	 * 这个方法会处理类中其他方法（被@RequestMapping注解）抛出的异常。
	 * @return
	 */
	@ExceptionHandler(UnauthorizedException.class)
	public String handleException(){
		return "redirect:/unauthorized.jsp";
	}
	
	@RequestMapping("/login")
	public String login(String username, String password, HttpServletRequest request){
		// 获取当前的Subject
        Subject currentUser = SecurityUtils.getSubject();
        // 测试当前的用户是否已经被认证，即是否已经登录
        if (!currentUser.isAuthenticated()) {
        	// 把用户名和密码封装为UsernamePasswordToken对象
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            //token.setRememberMe(true);
            try {
            	// 执行登录
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
            	// 没有这个用户
            	System.out.println("登录失败，用户【" + token.getPrincipal() + "】不存在！");
                return "redirect:/login.jsp";
            } catch (IncorrectCredentialsException ice) {
            	// 密码错误
            	System.out.println("登录失败，用户【" + token.getPrincipal() + "】密码不正确！");
            	return "redirect:/login.jsp";
            } catch (LockedAccountException lae) {
            	// 用户被锁定，禁用
            	System.out.println("登录失败，用户【" + token.getPrincipal() + "】被锁定！请联系管理员解锁");
            	return "redirect:/login.jsp";
            }
            catch (AuthenticationException ae) {
            	// 登录失败
            	System.out.println("登录失败");
            	return "redirect:/login.jsp";
            }
        }

        // 用户登录成功
        System.out.println("用户【" + currentUser.getPrincipal() + "】登录成功！");
        
        System.out.println( "=======ActiveSessions : "+ sessionDAO.getActiveSessions());
        SavedRequest savedRequest = WebUtils.getSavedRequest(request);
        if(null != savedRequest){
        	System.out.println("注意登录之前的路径是" + savedRequest.getRequestUrl());
        	System.out.println("注意登录之前的路径是" + savedRequest.getRequestUrl().substring(request.getContextPath().length()));
        	return "redirect:" +  savedRequest.getRequestUrl().substring(request.getContextPath().length());
        }
        else{
        	return "redirect:/list.jsp";
        }
	}

}
